// 简答题

// 一、请说出下列最终的执行结果，并解释为什么

// var a = [];
// for (let i = 0; i< 10; i++) {
//     console.log(i, "i");
//     a[i] = function() {
//         console.log(i);
//     }
// }


// a[6]();

// 结果是10， 这里 a[i] 函数的结果是 i的值，由于在执行的时候 i 已经变成了10 ，所以得到的结果是10。

// 如果把 var i = 0 替换成 let i = 0;


// 二、请说出下列最终的执行结果，并解释为什么

// var tmp = 123;

// if (true) {
//     console.log(tmp);
//     let tmp;
// }

// 这里会报错，因为 调用要放在声明的后面， 如果var的话有变量提升。

// 三、结合ES6 新语法，用最简单的方式找到数组中的最小值

// var arr = [12, 34, 32, 89, 4];

// arr.sort()[0];


// 四、请详细说明 var、let、 const 三种变量的方式之间的具体差别

//1、 var 有变量提升，let const  没有变量提升
// 2、块级作用域，let const 有块级作用域， var没有。使用 let 和 const 智能在快作用域里访问，不能跨快访问，也不能跨函数访问。
// 3、const 可以用来定义常量，使用是必须初始化，只能在块级作用域里访问，而且不能修改。
// 4、const 定义的对象属性如果定义的是基本属性是可以更改的，如果不是基本属性就可以更改。
// const仅仅保证指针不发生改变，修改对象的属性不会改变对象的指针。


// 五、请说出下列代码最终输出的结果，并解释为什么？

var a = 10;
var obj = {
    a: 20,
    fn () {
        setTimeout(() => {
            console.log(this.a);
        });
    }
}
obj.fn();

// 对象调用，所以这里的this 指向 obj obj作用域里的 a  是 20.

// 六 
// 1、我们可以使用 Symbol来作为对象属性名,要清楚的是 Symbol类型的  key是不能通过 Object.keys() 或者 for...in 枚举的，它违背包含在对象自身的属性集合中。
// 当使用JSON.stringify()将对象转换成JSON字符串的时候，Symbol属性也会被排除在输出内容之外：
// 2、使用Symbol来替代常量
// 3、使用Symbol定义类的私有属性/方法
// 我们知道在JavaScript中，是没有如Java等面向对象语言的访问控制关键字private的，类上所有定义的属性或方法都是可公开访问的。因此这对我们进行API的设计时造成了一些困扰。
// 而有了Symbol以及模块化机制，类的私有属性和方法才变成可能。

// 七

// 深拷贝是将一个对象从内存中完整得拷贝一份出来，从堆内存中重新开启一块新的区域来存放新的对象，且修改新对象不会影响原对象

// 浅拷贝是复制指向某个对象得指针，但并不会复制对象本身，新旧对象还是共享同一块内存。


// 八

// TypeScript 是 Microsoft 开发和维护的一种面向对象的编程语言。它是 JavaScript 的超集，包含了 JavaScript 的所有元素，可以载入 JavaScript 代码运行，并扩展了 JavaScript 的语法。

// 九

// （1）增强代码的可读性和可维护性，强类型的系统相当于最好的文档，在编译时即可发现大部分的错误，增强编辑器的功能。
// （2）包容性，js文件可以直接改成 ts 文件，不定义类型可自动推论类型，可以定义几乎一切类型，ts 编译报错时也可以生成 js 文件，兼容第三方库，即使不是用ts编写的
// （3）有活跃的社区，大多数的第三方库都可提供给 ts 的类型定义文件，完全支持 es6 规范
// 使用 TS 的缺点：
// （1）增加学习成本，需要理解接口（Interfaces）和泛型（Generics），类（class），枚举类型（Enums）
// （2）短期增加开发成本，增加类型定义，但减少维护成本
// （3）ts 集成到构建流程需要一定的工作量
// （4）和有些库结合时不是很完美


// 十、

// 引用计数法是GC算法之一。GC算法是内存管理中，垃圾回收器完成垃圾回收，从查找垃圾、释放空间到回收垃圾的一种规则。
// 引用计数法的原理:

// 引用计数算法的原理是设置一个引用数，判断当前引用数是否是0。
// 代码中有一个对象空间，多了一个变量名指向它，引用计数器就为它的引用数 + 1，减b少一个引用引用计数器就为它的引用数 - 1， 一旦引用数变为 0， 该对象空间就会被认为是垃圾，然后被回收。

// 引用计数算法的优点
// 发现了垃圾可以立即回收，一旦引用数为 0 就进行回收。
// 可以避免程序的暂停，因为一旦程序内存将要爆满的时候，引用计数就会找到垃圾并进行回收。

// 引用计数算法的缺点
// 无法回收循环引用的对象, 因为在如下代码中，在函数执行结束后，虽然 stone1 和 stone2 都无法被根访问到了，但是由于他们自身互相引用所以根据引用计数法的回收条件，是无法被回收的。

// 十一： 描述标记整理算法的整理流程
// 先遍历所有对象标记活动的对象，然后再一次遍历所有对象，先执行整理，移动对象的位置，将所有没有标记的对象地址连续起来，避免产生碎片化空间，然后清除这些没有标记的对象，回收相应的空间。

// 十二： 描述V8中新生代存储区垃圾回收的流程

// 回收过程采用复制算法+标记整理
// 新生代内存区分为二个等大小空间
// 使用空间为From，空闲空间为to
// 活动对象存储与于from空间
// 标记整理后将活动对象拷贝至To
// From与To交换空间完成释放

// 回收细节说明

// 拷贝过程中可能出现晋升
// 晋升就是将新生代对象移动至老生代
// 一轮GC还存活的新生代需要晋升
// To空间的使用率超过25%


// 十三

// 程序在标记阶段被暂停运行，等待标记完成自动运行，当遇到大块需要标记的对象时，程序需要暂停很长一段时间，对用户体验很不友好，因此采用增量标记，将一大块分解为多个小块进行标记，减少每次程序暂停的时长，优化用户体验。最后标记完成后统一进行回收。

